#include <GL/gl.h>
#include <SDL/SDL.h>
//#include <SDL/SDL_events.h>
//#include <SDL/SDL_video.h>
#include "sceneManager.h"
#include "meshManager.h"
#include "meshType.h"
#include "tetgenParser.h"

//The gui library
#include <guichan.hpp>
#include <guichan/sdl.hpp>
#include <guichan/opengl.hpp>
// A class used to load images for OpenGL using SDL
#include <guichan/opengl/openglsdlimageloader.hpp>
#include "keyListener.h"
#include "consoleWidget.h"
#include "baijiAccessor.h"

enum modeType {OBJECT, EDIT};
class Viewer;
typedef void ( *ptToSetMat ) ( void* );

struct DrawPoints
{
	Viewer* This;
	unsigned int idx;
	std::string meshName;
};

class Viewer
{
	protected:
		bool isRunning;
		unsigned int height;
		unsigned int width;
		bool isActive;
		MeshUtils::Vector3 camPos;
		MeshUtils::Vector3 camPosMove;
		MeshUtils::Quaternion camQuat;
		MeshUtils::Quaternion camQuatMove;
		double xMin;
		double yMin;
		double xMax;
		double yMax;

		//guichan
		gcn::SDLInput* input;
		gcn::OpenGLGraphics* graphics;
		gcn::SDLImageLoader* imageLoader;
		SDL_Surface* screen;
		Console* console;

		gcn::Gui* gui;
		gcn::Container* top;
		gcn::ImageFont* font;
		gcn::Label* label;


		SceneManager scnMng;
		MeshManager mshMng;
		int texture[6];
		GLuint records[16];

		double ambientLight[4];
		double diffuseLight[4];
		double positionLight[4];
		double lampPosition[4];
		modeType mode;

		std::map<unsigned int, bool> isPicked;

		//add setters and getters for lights properties
	public:
		inline void	setCamPos ( MeshUtils::Vector3 pos ) {camPos = pos; cout << camPos << endl;};
		inline void	setCamPosMove ( MeshUtils::Vector3 pos ) {camPosMove = pos;};
		inline void	setCamQuat ( MeshUtils::Quaternion q ) {camQuat = q;};
		inline void	setCamQuatMove ( MeshUtils::Quaternion q ) {camQuatMove = q;};

		Viewer ( unsigned int w, unsigned int h );
		~Viewer(void);

	private:
		void perspective ( double fov, double aspect, double zNear, double zFar );

		void drawScene ( ptToSetMat setMatp );
		void drawScenePoints ( ptToSetMat setMatp, void* setMapValue );
		void drawSceneInSelectionMode ( void );
		void loadGlTextures ( void );
		void loadSkyBox ( void );
		void initGl ( void );
		void pickMatrix ( double x, double y, double dx, double dy, int* viewport );
		void startPicking ( int x, int y, int dx, int dy );
		void stopPicking ( void );
		void displayInSelectionMode ( void );

		void display ( void );
		virtual void frameStart ( void ) = 0;
		virtual void frameEnd ( void ) = 0;
		virtual void handleEvent ( void ) = 0;
		virtual void buildScene ( void ) = 0;
		void run ( void );



	protected:
		void pickObject ( int x, int y );
		void pickEdit ( int x, int y );


	public:
		void start ( void );
		void drawTriangles ( ptToSetMat setMatp, std::vector<MeshUtils::Triangle>& tList );
		void drawPoints ( ptToSetMat setMatp, std::vector<MeshUtils::Vector3>& ptList, void* setMatValue );
		static void setMat ( void* );
		static void setMatForPoint ( void* drawInfo );
		static void setMatForPicking ( void* color );
};

class Baiji : public Viewer
{
		std::map<std::string, SceneNode*> nodes;
		bool rotating;
		bool zooming;
		bool picking;
		MeshUtils::Vector3 sphereStart;
		int zoomStart;

	public:
		inline Baiji ( unsigned int w, unsigned int h ) : Viewer ( w,h ), rotating ( false ), zooming ( false ), picking ( false ),  zoomStart ( false ) {};
		inline ~Baiji(void) {};
	private:
		void keyCallback ( const SDL_KeyboardEvent k );
		MeshUtils::Vector3 unProject ( const int x, const int y );
		void rotateCam ( const int x, const int y );
		void zoomCam ( const int x, const int y );
		void mouseCallback ( SDL_MouseButtonEvent, bool up );
		void motionCallback ( SDL_MouseMotionEvent );
		void frameStart ( void );
		void frameEnd();
		void handleEvent ( void );

	public:
		void addMesh ( MeshUtils::Mesh& msh, std::string name );
		Entity& createEntity ( std::string name, std::string mshName, std::string matName );
		void linkEntityToRoot ( std::string name );
		void buildScene ( void );
};
